package class_OuterInner;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by AJie on 2021/3/18
 * Function : 验证是否持有 外部类引用？
 * 直觉，
 * 全局变量 ，肯定持有外部类引用。（错误❌❌❌❌）
 * static class inner 不持有外部类引用。
 * <p>
 * 结论：
 * mhandler 全局变量的引用指向，堆。
 * outer 持有 mhandler 的引用。
 * mhandler 不持有 outer 的引用。
 * <p>
 * 特殊：
 * 内部类，匿名内部类，的构造方法中含有 外部类的入参。
 * 所以其，天生 持有外部类的引用。
 * <p>
 * 之前搞混的根源是，
 * 一般全局变量，不持有外部类的引用。
 * 是外部类持有此对象的引用。
 * 画个图就清晰了。
 */
public class Outer {
    public static void main(String[] args) {
        Outer outer = new Outer();
        System.out.println(outer);
        System.out.println("h1:");
        printField(outer.mHandler);
        System.out.println("h2:");
        printField(outer.mHandler2);
        System.out.println("h3:");
        printField(outer.mHandler3);
        System.out.println("\t");

        printField(outer.new Inner());//匿名内部类，持有外部类引用 this$0  --> Class_OuterInner.Outer@511d50c0
        System.out.println("\t");

        printField(outer.getAnonymousOther());
        System.out.println("\t");

        printField(outer.getOther());
        System.out.println("\t");
    }

    class Inner {
        public String publicString = "Inner.publicString";
    }

    Other anonymousOther = new Other() {//持有外部类引用 Class_OuterInner.Outer@511d50c0
        public String publicString = "Anonymous Class_OuterInner.Other.publicString";
    };

    public Other getAnonymousOther() {
        return anonymousOther;
    }

    Other Other = new Other();//没有持有外部类引用？？？ 无this$0 ???

    public Other getOther() {
        return Other;
    }

    MHandler mHandler = new MHandler();//不持有 class:Class_OuterInner.Outer$MHandler@60e53b93
    MHandler mHandler2 = new MHandler() {//匿名内部类，持有外部类引用，构造函数的入参。 this$0
        String strFile = "str2";
        //反射拿到2个 strFile ，2个值。虽然都是 declaredField.get(obj)
        //class:Class_OuterInner.Outer$2@76ed5528
        //strFile  --> str2
        //this$0  --> Class_OuterInner.Outer@27c170f0
        //strFile  --> str
    };

    MHandler mHandler3 = new MHandler();//不持有 class:Class_OuterInner.Outer$MHandler@60e53b93

    //     class MHandler{ //无 static， MHandler入参有外部类引用。mHandler3  持有外部类引用。
    static class MHandler {//有static，MHandler入参无外部类引用。 mHandler3 不持有外部类引用。
        String strFile = "str";
    }

    private static void printField(Object obj) {
        System.out.println("class:" + obj);
        try {
            List<Field> fieldList = new ArrayList<>();
            Class tempClass = obj.getClass();
            while (tempClass != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
                fieldList.addAll(Arrays.asList(tempClass.getDeclaredFields()));
                tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
            }

            for (int i = 0; i < fieldList.size(); i++) {
                Field declaredField = fieldList.get(i);
                declaredField.setAccessible(true);
                System.out.println(declaredField.getName() + "  --> " + declaredField.get(obj));
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

class Other {
    public String publicString = "Class_OuterInner.Other.publicString";
}
